/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package MyThread;

import MyLib.Comvar;
import MyLib.MyFile;
import Object.Torrent;
import java.awt.Font;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.JTextArea;

/**
 *
 * @author QuangHau
 */
public class DownLoadFile extends Thread {

    private Torrent torrenFile;
    private Object[] arrO;
    private ArrayList<DownloadChunk> ltDownloadChunk = new ArrayList<DownloadChunk>();
    private String path;
    private int numChunk;
    private boolean stopThread = false;
    private FindChunk findChunkThread = null;
    private Watting wthead = null;
    private JTextArea textArea;
    private JTable tbChunk;
    private boolean mergeChunk = false;
    private JLabel lbstart;

    public DownLoadFile(Torrent _torrenFile, String _path, int _numChunk, Object[] _arrO) {
        torrenFile = _torrenFile;
        arrO = _arrO;
        path = _path;
        numChunk = _numChunk;
        textArea = (JTextArea) arrO[2];
        tbChunk = (JTable) arrO[3];
        lbstart = (JLabel) arrO[4];
    }

    public void run() {
       Comvar.writeLog(1, DownLoadFile.class.getName(), "BEGIN DOWNLOAD FILE");
       /// String str = textArea.getText() + "======================================================\n";
        textArea.setText("");
        //textArea.setCaretPosition(textArea.getDocument().getLength());
        //textArea.setText(str);
       // textArea.setCaretPosition(textArea.getDocument().getLength());
        
       
        //find chunk
        if (doFindChunk()) {
            for (int i = 0; i < tbChunk.getRowCount(); i++) {
                tbChunk.setValueAt("Waiting...", i, 3);
            }
            //download chunk
            if (doDownloadChunk()) {
                //Merge Chunk
                mergeChunk = true;
                doMergeChunk();
            }
        } else {
            for (int i = 0; i < tbChunk.getRowCount(); i++) {
                tbChunk.setValueAt("Stopped", i, 3);
            }
        }
        JLabel stop = (JLabel) arrO[0];
        stop.setEnabled(false);
        stop.setFont(new Font("Tahoma", 0, 11));
        JLabel add = (JLabel) arrO[1];
        add.setEnabled(true);
        System.out.println("EXIT DOWNLOAD FILE THREAD");
        Comvar.writeLog(1, DownLoadFile.class.getName(), "END DOWNLOAD FILE");
    }

    private boolean doFindChunk() {
        textArea.setText(textArea.getText() + "Find chunk");
        textArea.setCaretPosition(textArea.getDocument().getLength());
        wthead = new Watting(textArea);
        wthead.start();

        findChunkThread = new FindChunk(torrenFile);
        findChunkThread.start();
        try {
            findChunkThread.join();
        } catch (InterruptedException ex) {
            Logger.getLogger(DownLoadFile.class.getName()).log(Level.SEVERE, null, ex);
        }

        if (stopThread) {
            wthead.stopWatting(": Cancel");
             try {
                wthead.join();
                lbstart.setEnabled(true);
            } catch (InterruptedException ex) {
                Logger.getLogger(DownLoadFile.class.getName()).log(Level.SEVERE, null, ex);
            }
            return false;
        } else {
            wthead.stopWatting(": OK");
            try {
                wthead.join();
            } catch (InterruptedException ex) {
                Logger.getLogger(DownLoadFile.class.getName()).log(Level.SEVERE, null, ex);
            }
            return true;
        }
    }

    private boolean doDownloadChunk() {
        textArea.setText(textArea.getText() + "Download chunk");
        textArea.setCaretPosition(textArea.getDocument().getLength());
        wthead = new Watting(textArea);
        wthead.start();

        int[] arrIndex = optimine();
        int idChunk = 0;
        while (isDownloaded()== 0) {
            try {
                while (!stopThread && countThread() < numChunk && ltDownloadChunk.size() != torrenFile.getChunks().size()) {
                    if (ltDownloadChunk.size() <= torrenFile.getChunks().size()) {
                        int row = 0;
                        for (int j = 0; j < tbChunk.getRowCount(); j++) {
                            if (tbChunk.getValueAt(j, 0).equals(Integer.toString(arrIndex[idChunk]))) {
                                row = j;
                                break;
                            }
                        }
                        DownloadChunk downloadThread = new DownloadChunk(torrenFile, arrIndex[idChunk], tbChunk, row);
                        downloadThread.start();
                        ltDownloadChunk.add(downloadThread);
                        idChunk++;
                        Thread.sleep(100);
                    }

                }
                if (ltDownloadChunk.size() != torrenFile.getChunks().size()) {
                    //Comvar.threadDownloadFile.tryAcquire(5, TimeUnit.SECONDS);
                    Comvar.threadDownloadFile.tryAcquire(4, TimeUnit.SECONDS);

                }
            } catch (InterruptedException ex) {
                Comvar.threadDownloadFile.release();
            }
        }
        
        if (isDownloaded() == -1) {//dung do stop
            wthead.stopWatting(": Cancel");
            for(int i=0; i<tbChunk.getRowCount(); i++)
            {
                if(tbChunk.getValueAt(i, 3).equals("Waiting...")){
                    tbChunk.setValueAt("Stopped", i, 3);
                }
            }
            try {
                wthead.join();
                lbstart.setEnabled(true);
            } catch (InterruptedException ex) {
                Logger.getLogger(DownLoadFile.class.getName()).log(Level.SEVERE, null, ex);
            }
            return false;
        } else {//dung binh tuong --> down load thanh cong
            wthead.stopWatting(": OK");
            try {
                wthead.join();
            } catch (InterruptedException ex) {
                Logger.getLogger(DownLoadFile.class.getName()).log(Level.SEVERE, null, ex);
            }
            return true;
        }
    }

    private void doMergeChunk() {
        textArea.setText(textArea.getText() + "Write file");
        textArea.setCaretPosition(textArea.getDocument().getLength());
        wthead = new Watting(textArea);
        wthead.start();

        MyFile.mergeParts(torrenFile, path);

        wthead.stopWatting(": OK");
        try {
            wthead.join();
        } catch (InterruptedException ex) {
            Logger.getLogger(DownLoadFile.class.getName()).log(Level.SEVERE, null, ex);
        }
        textArea.setText(textArea.getText() + "Successful!!!\n");
    }
    
    private int countThread() {
        int count = 0;
        for (int i = 0; i < ltDownloadChunk.size(); i++) {
            if (ltDownloadChunk.get(i).isAlive()) {
                count++;
            }
        }
        return count;
    }

    private int isDownloaded() {
        if (ltDownloadChunk.isEmpty()) {
            return 0;
        }
        
        for (int i = 0; i < ltDownloadChunk.size(); i++) {
            if (ltDownloadChunk.get(i).isAlive()) {
                return 0;
            }
        }
        
        if (ltDownloadChunk.size() == torrenFile.getChunks().size()) {
            int count = 0;
            for (int i = 0; i < ltDownloadChunk.size(); i++) {
                if (!ltDownloadChunk.get(i).getDownloadChunk()) {
                    count++;
                }
            }
            if (count == ltDownloadChunk.size()) {
                //cac thread dung binh thuong
                return 1;
            } else {
                //dung do stop
                return -1;
            }
        }
        else {
            //ket thuc do stop
            if (stopThread) {
                return -1;
            } else {
                return 0;
            }
        }
    }

    public boolean stopDownloadFile() {
        if(mergeChunk){
            return false;
        }
        
        if (findChunkThread != null && findChunkThread.isAlive()) {
            findChunkThread.stopFindChunk();
        } else {
            for (int i = 0; i < ltDownloadChunk.size(); i++) {
                if (ltDownloadChunk.get(i).isAlive()) {
                    ltDownloadChunk.get(i).stopDownloadChunk();
                }
            }
        }
        stopThread = true;
        Comvar.threadDownloadFile.release();
        try {
            this.join();
        } catch (InterruptedException ex) {
            Logger.getLogger(DownLoadFile.class.getName()).log(Level.SEVERE, null, ex);
        }
        return true;
    }
    
    private int[] optimine() {
        int[] result = new int[Comvar.listChunkIP.size()];
        int[] lst_chunkDown = new int[Comvar.listChunkIP.size()];
        for (int i = 0; i < Comvar.listChunkIP.size(); i++) {
            lst_chunkDown[i] = Comvar.listChunkIP.get(i).size();
        }
        int min = 0;
        for (int i = result.length - 1; i >= 0; i--) {
            for (int j = 0; j < lst_chunkDown.length; j++) {
                if (lst_chunkDown[min] <= lst_chunkDown[j]) {
                    min = j;
                }
            }
            lst_chunkDown[min] = -1;
            result[i] = min;
        }
        for (int i = 0; i < result.length; i++) {
            System.out.print(result[i] + "\t");
        }
        return result;
    }
}
